home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
TCPSUBR.C
< prev
next >
Wrap
Text File
|
1993-08-09
|
6KB
|
292 lines
/* Low level TCP routines:
* control block management
* sequence number logical operations
* state transitions
* RTT cacheing
*
* Copyright 1991 Phil Karn, KA9Q
*/
#include <stdio.h>
#include "global.h"
#include "timer.h"
#include "mbuf.h"
#include "netuser.h"
#include "internet.h"
#include "tcp.h"
#include "ip.h"
/* TCP connection states */
char *Tcpstates[] = {
"",
"Closed",
"Listen",
"SYN sent",
"SYN rcvd",
"Established",
"FIN wait 1",
"FIN wait 2",
"Close wait",
"Last ACK",
"Closing",
"Time wait"
};
/* TCP closing reasons */
char *Tcpreasons[] = {
"Normal",
"Reset/Refused",
"Timeout",
"ICMP"
};
int16 Tcp_mss = DEF_MSS; /* Maximum segment size to be sent with SYN */
int32 Tcp_irtt = DEF_RTT; /* Initial guess at round trip time */
int Tcp_trace = FALSE; /* State change tracing flag */
int Tcp_syndata = FALSE;
struct tcp_rtt Tcp_rtt[RTTCACHE];
struct tcb *Tcbs = NULLTCB;
struct mib_entry Tcp_mib[] = {
NULLCHAR, 0,
"RtoAlgorithm", 4, /* Van Jacobsen's algorithm */
"RtoMin", 0, /* No lower bound */
"RtoMax", MAXINT32, /* No upper bound */
"MaxConn", -1L, /* No limit */
"ActiveOpens", 0,
"PassiveOpens", 0,
"AttemptFails", 0,
"EstabResets", 0,
"CurrEstab", 0,
"InSegs", 0,
"OutSegs", 0,
"RetransSegs", 0,
NULLCHAR, 0, /* Connection state goes here */
"InErrs", 0,
"OutRsts", 0,
};
/* Look up TCP connection
* Return TCB pointer or NULLTCB if nonexistant.
* Also move the entry to the top of the list to speed future searches.
*/
struct tcb *
lookup_tcb(struct connection *conn)
{
struct tcb *tcb, *tcblast = NULLTCB;
for(tcb = Tcbs; tcb != NULLTCB; tcblast = tcb, tcb = tcb->next) {
/* Yet another structure compatibility hack */
if(conn->remote.port == tcb->conn.remote.port
&& conn->local.port == tcb->conn.local.port
&& conn->remote.address == tcb->conn.remote.address
&& conn->local.address == tcb->conn.local.address) {
if(tcblast != NULLTCB) {
/* Move to top of list */
tcblast->next = tcb->next;
tcb->next = Tcbs;
Tcbs = tcb;
}
return tcb;
}
}
return NULLTCB;
}
/* Create a TCB, return pointer. Return pointer if TCB already exists. */
struct tcb *
create_tcb(struct connection *conn)
{
struct tcb *tcb;
if((tcb = lookup_tcb(conn)) == NULLTCB) {
struct tcp_rtt *tp;
tcb = mxallocw(sizeof(struct tcb));
ASSIGN(tcb->conn,*conn);
tcb->state = TCP_CLOSED;
tcb->cwind = tcb->mss = Tcp_mss;
tcb->ssthresh = 65535L;
if((tp = rtt_get(tcb->conn.remote.address)) != NULLRTT) {
tcb->srtt = tp->srtt;
tcb->mdev = tp->mdev;
} else {
tcb->srtt = Tcp_irtt; /* mdev = 0 */
}
/* Initialize timer intervals */
tcb->timer.func = tcp_timeout;
tcb->timer.arg = tcb;
set_timer(&tcb->timer,tcb->srtt);
tcb->next = Tcbs;
Tcbs = tcb;
}
return tcb;
}
/* Close our TCB */
void
close_self(struct tcb *tcb,int reason)
{
if(tcb != NULLTCB) {
struct reseq *res, *restmp = NULLRESEQ;
stop_timer(&tcb->timer);
/* Flush reassembly queue; nothing more can arrive */
for(res = tcb->reseq; res != NULLRESEQ; res = restmp) {
restmp = res->next;
free_p(res->bp);
xfree(res);
}
tcb->reseq = NULLRESEQ;
tcb->reason = reason;
setstate(tcb,TCP_CLOSED);
}
}
/* Sequence number comparisons
* Return true if x is between low and high inclusive,
* false otherwise
*/
int
seq_within(int32 x,int32 low,int32 high)
{
if(low <= high) {
if(low <= x && x <= high) {
return 1;
}
} else {
if(low >= x && x >= high) {
return 1;
}
}
return 0;
}
int
seq_lt(int32 x,int32 y)
{
return (long)(x-y) < 0;
}
#ifdef XXX
int
seq_le(int32 x,int32 y)
{
return (int)(x-y) <= 0;
}
#endif
int
seq_gt(int32 x,int32 y)
{
return (long)(x-y) > 0;
}
int
seq_ge(int32 x,int32 y)
{
return (long)(x-y) >= 0;
}
void
setstate(struct tcb *tcb,int newstate)
{
int oldstate = tcb->state;
tcb->state = newstate;
if(Tcp_trace && !uploadstatus)
tprintf("TCB %lx %s -> %s\n",ptol(tcb),
Tcpstates[oldstate],Tcpstates[newstate]);
/* Update MIB variables */
switch(oldstate){
case TCP_CLOSED:
if(newstate == TCP_SYN_SENT)
tcpActiveOpens++;
break;
case TCP_LISTEN:
if(newstate == TCP_SYN_RECEIVED)
tcpPassiveOpens++;
break;
case TCP_SYN_SENT:
if(newstate == TCP_CLOSED)
tcpAttemptFails++;
break;
case TCP_SYN_RECEIVED:
switch(newstate){
case TCP_CLOSED:
case TCP_LISTEN:
tcpAttemptFails++;
break;
}
break;
case TCP_ESTABLISHED:
case TCP_CLOSE_WAIT:
switch(newstate){
case TCP_CLOSED:
case TCP_LISTEN:
tcpEstabResets++;
break;
}
tcpCurrEstab--;
break;
}
if(newstate == TCP_ESTABLISHED || newstate == TCP_CLOSE_WAIT)
tcpCurrEstab++;
if(tcb->s_upcall)
(*tcb->s_upcall)(tcb,oldstate,newstate);
switch(newstate){
case TCP_SYN_RECEIVED:
case TCP_ESTABLISHED:
/* Notify the user that he can begin sending data */
if(tcb->t_upcall)
(*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
break;
}
}
/* Round trip timing cache routines.
* These functions implement a very simple system for keeping track of
* network performance for future use in new connections.
* The emphasis here is on speed of update (rather than optimum cache hit
* ratio) since rtt_add is called every time a TCP connection updates
* its round trip estimate.
*/
void
rtt_add(int32 addr,int32 rtt)
{
if(addr != 0) {
struct tcp_rtt *tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
if(tp->addr != addr) {
/* New entry */
tp->addr = addr;
tp->srtt = rtt;
tp->mdev = 0;
} else {
/* Run our own SRTT and MDEV integrators, with rounding */
int32 abserr = (rtt > tp->srtt) ? rtt - tp->srtt : tp->srtt - rtt;
tp->srtt = ((AGAIN-1) * tp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
tp->mdev = ((DGAIN-1) * tp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
}
}
}
struct tcp_rtt *
rtt_get(int32 addr)
{
struct tcp_rtt *tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
if(addr == 0 || tp->addr != addr)
return NULLRTT;
return tp;
}